home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / MAC / THINKC / TCL1 / GRAPH_FO / (GRAPH / GRAPH_SO / GRAPH.C next >
Text File  |  1991-04-09  |  9KB  |  403 lines

  1. /******************************************************************************
  2.     Graph.c
  3.         Graph methods in Object C.
  4.  
  5.     SUPERCLASS = CObject
  6.  
  7.     Copyright ⌐ 1991 Maarten Meijer. All rights reserved.
  8.         CIS 100016,1764; FidoNet 2:512/114
  9. *******************************************************************************/
  10.  
  11. /* includes */
  12. #include <CError.h>
  13. #include "GraphCommands.h"
  14. #include "Graph.h"
  15. #include "CLinkTask.h"
  16. #include "CSelRectTask.h"
  17. #include "CMoveTask.h"
  18.  
  19. /* externs */
  20. extern    CError    *gError;
  21.  
  22. /* methods */
  23. /******************************************************************************
  24.     IGraph
  25.  
  26.         Initialize a graph structure,
  27.         thePane    :    the enclosing Panorama/Pane
  28.         flags    :    should be used to determine :
  29.                 Ñ    undirected vs. directed graph
  30.                 Ñ    single vs multigraph
  31.                 Ñ    weighed edges (also select edges)
  32.                 Ñ    vert. and hor. alignment
  33.         grid    :     the grid size as Point
  34. *******************************************************************************/
  35.  
  36. void
  37. Graph::IGraph(CPanorama *thePane, short flags, Point grid) {
  38.     vertexList = (GrList *)new(GrList);
  39.     vertexList->IGrList();
  40.     edgeList = (GrList *)new(GrList);
  41.     edgeList->IGrList();
  42.     _grid = grid;
  43.     _flags = flags;
  44.     itsPane = thePane;
  45.     }
  46.  
  47.  
  48. /******************************************************************************
  49.     Dispose
  50. *******************************************************************************/
  51. void
  52. Graph::Dispose() {
  53.     edgeList->DisposeAll();        /* CCluster */
  54.     vertexList->DisposeAll();    /* CCluster */
  55.     inherited::Dispose();        /* CObject */
  56.     }
  57.  
  58. Point
  59. Graph::Align(Point pt) {
  60.     Point    new;
  61.     new = pt;
  62.     if(_grid.h && (_flags & grHAlign))
  63.         new.h = (pt.h / _grid.h) * _grid.h + (_grid.h >> 1);    /* align to grid */
  64.     if(_grid.v && (_flags & grVAlign))
  65.         new.v = (pt.v / _grid.v) * _grid.v + (_grid.v >> 1);
  66.     return new;
  67.     }
  68.  
  69. /******************************************************************************
  70.     Draw
  71.  
  72.         Draw the area in the rectangle area. This could probably look better
  73.         if drawing was into an offscreen bitmap, and the copy into the pane.
  74. *******************************************************************************/
  75. void
  76. Graph::Draw(Rect *area) {
  77.     long    finalTicks;
  78.  
  79.     if(_flags & grDebug) {
  80.         PenPat(gray);
  81.         PaintRect(area);
  82.         PenNormal();
  83.         Delay(60, &finalTicks);
  84.         }
  85.  
  86.     EraseRect(area);
  87.     edgeList->Draw(area);
  88.     vertexList->Draw(area);
  89.     }
  90.  
  91. /******************************************************************************
  92.     NewVertex
  93.  
  94.         Create a new vertex, makes it easier to override the creation of
  95.         vertices.
  96. *******************************************************************************/
  97. GrVertex *
  98. Graph::NewVertex() {
  99.     register GrVertex *vertex;
  100.  
  101.     vertex = (GrVertex *)new(GrVertex);
  102.     vertex->IGraphNode();
  103.     return vertex;
  104.     }
  105.  
  106. /******************************************************************************
  107.     newEdge
  108.  
  109.         Create a new edge, makes it easier to override the creation of edges.
  110. *******************************************************************************/
  111. GrEdge *
  112. Graph::NewEdge() {
  113.     register GrEdge *edge;
  114.  
  115.     edge = (GrEdge *)new(GrEdge);
  116.     edge->IGraphNode();
  117.     return edge;
  118.     }
  119.  
  120. /******************************************************************************
  121.     AddVertex
  122.  
  123.         Create vertex and add to the vertexlist.
  124. *******************************************************************************/
  125. GrVertex *
  126. Graph::AddVertex(Point center, Boolean redraw) {
  127.     GrVertex *        newVertex;
  128.  
  129.     newVertex = NewVertex();
  130.     vertexList->AddNode((GrNode *)newVertex);
  131.  
  132.     newVertex->SetCenter(Align(center));
  133.     return (newVertex);
  134.     }
  135.  
  136. void
  137. Graph::RemoveVertex(GrVertex *whichVertex, Boolean redraw) {
  138.     GrEdge *        whichEdge;
  139.     Rect            area, rect;
  140.     Point            ctr;
  141.  
  142.     if(whichVertex == (GrNode *)NULL)
  143.         return;
  144.     if(redraw)
  145.         whichVertex->GetRect(&area);
  146.     do {
  147.         whichEdge = (GrEdge *)edgeList->FindIncident(whichVertex);
  148.         if(whichEdge != (GrEdge *)NULL) {
  149.             if(redraw) {
  150.                 whichEdge->GetRect(&rect);
  151.                 UnionRect(&rect, &area, &area);
  152.                 }
  153.             edgeList->RemoveNode(whichEdge);
  154.             }
  155.     } while(whichEdge != (GrEdge *)NULL);
  156.     vertexList->RemoveNode(whichVertex);
  157.     if(redraw)
  158.         itsPane->RefreshRect(&area);
  159.     }
  160.  
  161. GrEdge *
  162. Graph::AddEdge(GrVertex *from, GrVertex *to, Boolean redraw) {
  163.     Rect            area;
  164.     GrEdge    *        newEdge;
  165.  
  166.     if( ( !(_flags & grSelfRef)    ) &&
  167.         ( from == to ) ) {
  168.             gError->PostAlert(grErrID, grNoSelfErr);
  169.             return NULL;
  170.             }
  171.     if((_flags & grMulti) == 0) {
  172.         if(_flags & grDirected) {    /* Check first if it is allready there */
  173.             if(AdjacentTo(from, to)) {
  174.                 gError->PostAlert(grErrID, grMultiErr);
  175.                 return NULL;
  176.                 }
  177.             }
  178.         else {
  179.             if(Adjacent(from, to)) {
  180.                 gError->PostAlert(grErrID, grMultiErr);
  181.                 return NULL;
  182.                 }
  183.             }
  184.         }
  185.  
  186.     newEdge = NewEdge();
  187.     newEdge->SetFrom(from);
  188.     newEdge->SetTo(to);
  189.     edgeList->AddNode((GrNode *)newEdge);
  190.     if(redraw) {
  191.         newEdge->GetRect(&area);
  192.         itsPane->RefreshRect(&area);
  193.         }
  194.     return(newEdge);
  195.     }
  196.  
  197. void
  198. Graph::RemoveEdge(GrEdge * whichEdge, Boolean redraw) {
  199.     Rect            area;
  200.  
  201.     if(whichEdge != (GrEdge *)NULL) {
  202.         if(redraw)
  203.             whichEdge->GetRect(&area);
  204.         edgeList->RemoveNode(whichEdge);
  205.         if(redraw)
  206.             itsPane->RefreshRect(&area);
  207.         }
  208.     }
  209.  
  210.  
  211. void
  212. Graph::SetVertexCenter(GrVertex *which, Point where, Boolean redraw) {
  213.     Rect    area;
  214.  
  215.     if(redraw) {
  216.         edgeList->SpanningRect(which, &area);
  217.         itsPane->RefreshRect(&area);
  218.         }
  219.  
  220.     which->SetCenter(Align(where));
  221.  
  222.     if(redraw) {
  223.         edgeList->SpanningRect(which, &area);
  224.         itsPane->RefreshRect(&area);
  225.         }
  226.     }
  227.  
  228. /******************************************************************************
  229.     Deselect
  230.  
  231.         Deselect all vertices and edges in the graph.
  232. *******************************************************************************/
  233. void
  234. Graph::Deselect() {
  235.     vertexList->Deselect();
  236.     edgeList->Deselect();
  237.     }
  238.  
  239.  
  240. void
  241. Graph::GetGrid(Point *grid) {
  242.     *grid = _grid;
  243.     }
  244.  
  245. GrVertex *
  246. Graph::FindVertex(Point where) {
  247.     return (GrVertex *)vertexList->FindNode(where);
  248.     }
  249.  
  250. GrEdge *
  251. Graph::FindEdge(Point where) {
  252.     return (GrEdge *)edgeList->FindNode(where);
  253.     }
  254.  
  255.  
  256. /******************************************************************************
  257.     Testing for adjacency of two vertices
  258.         (This should depend on MultiGraph/DiGraph flags, but does not for
  259.         the moment)
  260.  
  261.     suppose:    v1 ----> v2
  262.         AdjacentTo(v1,v2)        returns TRUE    (if digraph)
  263.         AdjacentFrom(v1,v2)        returns FALSE    (if digraph)
  264.         Adjacent(v1,v2)            returns TRUE    (if not digraph)
  265. *******************************************************************************/
  266. static    GrVertex *tv1, *tv2;
  267.  
  268. static    Boolean
  269. _AdjacentTo(GrEdge *edge) {
  270.     return(    (tv1 == edge->fromVertex) &&
  271.             (tv2 == edge->toVertex    ) );
  272.     }
  273.  
  274.  
  275. Boolean
  276. Graph::AdjacentTo(GrVertex *v1, GrVertex *v2) {
  277.     tv1 = v1;
  278.     tv2 = v2;
  279.     return(edgeList->FindItem(_AdjacentTo) != NULL);
  280.     }
  281.  
  282. Boolean
  283. Graph::AdjacentFrom(GrVertex *v1, GrVertex *v2) {
  284.     tv1 = v2;
  285.     tv2 = v1;
  286.     return(edgeList->FindItem(_AdjacentTo) != NULL);
  287.     }
  288.  
  289. Boolean
  290. Graph::Adjacent(GrVertex *v1, GrVertex *v2) {
  291.     return ( AdjacentTo(v1, v2) || AdjacentFrom(v1, v2) );
  292.     }
  293.  
  294. /******************************************************************************
  295.     SetOptions
  296.  
  297.         Set the options for demo purposes with a dialog.
  298. *******************************************************************************/
  299.  
  300. static pascal Boolean
  301. numkeyfilter(DialogPtr dlg, EventRecord *evt, short *itemHit) {
  302.     char    temp;
  303.  
  304.     if(    ((evt->what == keyDown) || (evt->what == autoKey)) ) {
  305.              temp = evt->message & charCodeMask;
  306.              if(temp >= '0' && temp <= '9') {
  307.                  return    false;
  308.                  }
  309.              else if(temp == '\t' || temp == 8) {
  310.                  return false;
  311.                  }
  312.              else if(temp == 3 || temp == '\r') {
  313.                 *itemHit = ITEMcancel;
  314.                 return true;
  315.                  }
  316.              else {
  317.                  SysBeep(2);
  318.                  return true;
  319.                  }
  320.         }
  321.     return false;
  322.     }
  323.  
  324.  
  325. void
  326. Graph::SetOptions() {
  327.     DialogPtr            dlg;
  328.     short                itemHit, kind;
  329.     register short        item, value, newflags;
  330.     Handle                h;
  331.     Rect                r;
  332.     ControlHandle        CItem;
  333.     long                number;
  334.     Str255                numStr;
  335.  
  336.     dlg = GetNewDialog(DLOGoptions, NULL, (WindowPtr)(-1));
  337.     SetOutlineButton(dlg, ITEMcancel, ITEMoutline);
  338.     SelIText(dlg, ITEMhgrid, 0, 32767);
  339.     ShowWindow((WindowPtr)dlg);
  340.     SetPort((GrafPtr)dlg);
  341.  
  342.     for(item = ITEMhalign; item <= ITEMdebug; ++item) {
  343.         if(_flags & (1 << (item - ITEMhalign)))
  344.             value = 1;
  345.         else
  346.             value = 0;
  347.         GetDItem(dlg, item, &kind, &h, &r);
  348.         CItem = (ControlHandle)h;
  349.         SetCtlValue(CItem, value);
  350.         }
  351.  
  352.     NumToString((long)_grid.h, numStr);
  353.     GetDItem(dlg, ITEMhgrid, &kind, &h, &r);
  354.     SetIText(h, numStr);
  355.     NumToString((long)_grid.v, numStr);
  356.     GetDItem(dlg, ITEMvgrid, &kind, &h, &r);
  357.     SetIText(h, numStr);
  358.  
  359.     do {
  360.         ModalDialog(numkeyfilter, &itemHit);
  361.         switch(itemHit) {
  362.             case ITEMhalign:
  363.             case ITEMvalign:
  364.             case ITEMdigraph:
  365.             case ITEMmulti:
  366.             case ITEMdebug:
  367.             case ITEMselfref:
  368.  
  369.                 GetDItem(dlg, itemHit, &kind, &h, &r);
  370.                 CItem = (ControlHandle)h;
  371.                 value = GetCtlValue(CItem);
  372.                 SetCtlValue(CItem, ((value + 1) & 1));
  373.                 break;
  374.             }
  375.     } while ( (itemHit != ITEMok) && (itemHit != ITEMcancel) );
  376.  
  377.     if(itemHit == ITEMok) {
  378.         newflags = 0;
  379.         for(item = ITEMhalign; item <= ITEMdebug; ++item) {
  380.             GetDItem(dlg, item, &kind, &h, &r);
  381.             CItem = (ControlHandle)h;
  382.             value = GetCtlValue(CItem);
  383.             newflags |= (value << (item - ITEMhalign));
  384.             }
  385.         _flags = newflags;
  386.  
  387.         GetDItem(dlg, ITEMhgrid, &kind, &h, &r);
  388.         GetIText(h, numStr);
  389.         StringToNum(numStr, &number);
  390.         if(number < 300)
  391.             _grid.h = (short)number;
  392.  
  393.         GetDItem(dlg, ITEMvgrid, &kind, &h, &r);
  394.         GetIText(h, numStr);
  395.         StringToNum(numStr, &number);
  396.         if(number < 300)
  397.             _grid.v = (short)number;
  398.  
  399.         }
  400.  
  401.     DisposDialog(dlg);
  402.     }
  403.